package com.ciaojian.client.service;

import cn.hutool.core.util.RandomUtil;
import com.ciaojian.client.policy.factory.ProductHandleFactory;
import com.ciaojian.core.enums.business.OrderOrderTypeEnum;
import com.ciaojian.core.enums.business.OrderStatusEnum;
import com.ciaojian.core.enums.business.PayTypeEnum;
import com.ciaojian.core.mapper.UserTimesCardMapper;
import com.ciaojian.core.model.*;
import com.ciaojian.core.model.dto.StoreDTO;
import com.ciaojian.core.service.PayService;
import com.ciaojian.core.service.ProductHandleService;
import com.ciaojian.core.service.UserTimesCardService;
import com.ciaojian.core.util.BigDecimalUtil;
import com.ciaojian.core.util.LogUtil;
import com.ciaojian.core.util.StringUtil;
import com.ciaojian.pay.core.enums.SignType;
import com.ciaojian.pay.core.kit.WxPayKit;
import com.ciaojian.pay.wxpay.WxPayApi;
import com.ciaojian.pay.wxpay.model.request.UnifiedOrderModel;
import com.ciaojian.pay.wxpay.model.response.UnifiedOrderModelResponse;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/**
 * @author oxiny
 */
@Service
public class PayServiceImpl extends PayService {
    @Resource
    private OrderServiceImpl orderService;
    @Resource
    private UserTimesCardService<UserTimesCardMapper, UserTimesCard> userTimesCardService;
    @Resource
    private WorkerInviteServiceImpl workerInviteService;
    @Resource
    private StoreServiceImpl storeService;

    @Override
    public Map<String, Object> pay(ProductGroup productGroup,
                                   User user,
                                   String openId,
                                   WxPayBase wxPayBean,
                                   OrderOrderTypeEnum orderType,
                                   HttpServletRequest request) throws IllegalAccessException {
        // 生成订单号
        String orderNo = userTimesCardService.generateOrderNo();
        String body = productGroup.getName();
        // 根据UserId 查询 WorkerId
        Integer workerId = workerInviteService.getWorkerIdByUserId(user.getId());
        StoreDTO storeDTO = storeService.getBaseMapper().findByWorkerId(workerId);
        try {
            if (storeDTO != null) {
                body = storeDTO.getTitle().concat("-").concat(body);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.writeErrorLog(e.getMessage());
        }

        // 生成订单
        Order order = new Order().setUserId(user.getId())
                .setStatus(OrderStatusEnum.wait_notify)
                .setProductGroupId(productGroup.getId())
                .setType(productGroup.getName())
                .setOrderType(orderType)
                .setPayType(PayTypeEnum.WECHAT_PAY.getDescription())
                .setGoodsTotal(BigDecimalUtil.reduce(BigDecimal.valueOf(productGroup.getPrice()), BigDecimalUtil.HUNDRED))
                .setOrderNo(orderNo);
        orderService.setWorker(order);
        order.insert();

        Map<String, Object> params = UnifiedOrderModel
                .builder()
                .appid(wxPayBean.getAppId())
                .mch_id(wxPayBean.getMchId())
                .nonce_str(RandomUtil.randomString(32))
                .body(body)
                .out_trade_no(orderNo)
                .total_fee(String.valueOf(productGroup.getPrice()))
                .spbill_create_ip(StringUtil.getIpAddr(request))
                .notify_url(wxPayBean.getDomain().concat("/client/notify/product-group"))
                .trade_type(wxPayBean.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPayBean.getKey(), SignType.MD5);

        // 判断购买限制
        buyLimit(productGroup, user);

        LogUtil.writePayLog(">>>购买次卡支付方法>>>请求参数:{params:{}}", params);
        // 返回 xml 格式表单
        String xmlResult = WxPayApi.pushOrder(params);
        UnifiedOrderModelResponse response = WxPayKit.xmlToBean(xmlResult, UnifiedOrderModelResponse.class);
        LogUtil.writePayLog(">>>payMethod,支付请求返回参数={}>>>", response.toString());

        // 判断请求结果
        WxPayKit.codeIsOk(response);

        // 微信支付返回的预支付id
        String prepayId = response.getPrepay_id();
        // 二次签名，构建公众号唤起支付的参数,这里的签名方式要与上面统一下单请求签名方式保持一致

        // 将二次签名构建的数据返回给前端并唤起小程序支付
        return WxPayKit.miniAppPrepayIdCreateSign(
                wxPayBean.getAppId(),
                prepayId,
                wxPayBean.getKey(),
                SignType.MD5);
    }


    @Override
    public Map<String, Object> pay2(Order order, String openId, WxPayBase wxPay, OrderOrderTypeEnum orderType, HttpServletRequest request) throws IllegalAccessException {
        Map<String, Object> params = UnifiedOrderModel
                .builder()
                .appid(wxPay.getAppId())
                .mch_id(wxPay.getMchId())
                .nonce_str(RandomUtil.randomString(32))
                .body(order.getType())
                .out_trade_no(order.getOrderNo())
                .total_fee(order.getPayTotal().toString())
                .spbill_create_ip(StringUtil.getIpAddr(request))
                .notify_url(wxPay.getDomain().concat("/client/notify/wxNotify/member-card"))
                .trade_type(wxPay.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPay.getKey(), SignType.MD5);
        LogUtil.writePayLog(">>>调起收银台>>>请求参数:{params:{}}", params);
        // 返回 xml 格式表单
        String xmlResult = WxPayApi.pushOrder(params);
        UnifiedOrderModelResponse response = WxPayKit.xmlToBean(xmlResult, UnifiedOrderModelResponse.class);
        LogUtil.writePayLog(">>>payMethod,支付请求返回参数={}>>>", response.toString());

        // 新增订单支付记录
        OrderPayment orderPayment = new OrderPayment();
        // 判断请求结果
        try {
            WxPayKit.codeIsOk(response);
            orderPayment.setOrderNo(order.getOrderNo());
            orderPayment.setPayType(0);
            orderPayment.setPostStatus(2);
            orderPayment.setAmount(order.getPayTotal().intValue());
            orderPayment.setPostJson(params.toString());
            orderPayment.setRawResult(xmlResult);
            orderPayment.setAddTime(order.getAddTime());
            orderPayment.setSuccessTime(new Date());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            orderPayment.setPostStatus(1);
            orderPayment.setReturnErrCode(response.getErr_code());
            orderPayment.setReturnErrStr(response.getErr_code_des());
            throw e;
        } finally {
            orderPayment.insert();
        }


        // 微信支付返回的预支付id
        String prepayId = response.getPrepay_id();
        // 二次签名，构建公众号唤起支付的参数,这里的签名方式要与上面统一下单请求签名方式保持一致
        return WxPayKit.miniAppPrepayIdCreateSign(
                wxPay.getAppId(),
                prepayId,
                wxPay.getKey(),
                SignType.MD5);
    }

    private void buyLimit(ProductGroup productGroup, User user) {
        productGroup.getProductGroupDetailList()
                .forEach(productGroupDetail -> {
                    ProductHandleService handleService = ProductHandleFactory.getMedalService(productGroupDetail.getType());
                    handleService.checkLimit(user, productGroupDetail.getProductId());
                });
    }
}
